use crate::extension::index::selector::label_selector::equality_matcher::EqualityMatcher;
use crate::extension::index::selector::label_selector::set_matcher::{Operator, SetMatcher};
use crate::utils::str_util;
use ordermap::OrderSet;
use std::collections::HashMap;
use std::fmt::{Display, Formatter};

pub trait SelectorMatcher {
    fn get_key(&self) -> String;

    /**
     * Returns true if a field value matches.
     *
     * @param s the field value
     * @return the boolean
     */
    fn test(&self, s: String) -> bool;
}

pub enum SelectorMatchers {
    EqualityMatcher(equality_matcher::EqualityMatcher),
    SetMatcher(set_matcher::SetMatcher),
}

// 为 EqualityMatcher 实现 SelectorMatcher trait
impl SelectorMatcher for SelectorMatchers {
    fn get_key(&self) -> String {
        match self {
            SelectorMatchers::EqualityMatcher(it) => it.key.clone(),
            SelectorMatchers::SetMatcher(it) => it.key.clone(),
        }
    }

    fn test(&self, s: String) -> bool {
        match self {
            SelectorMatchers::EqualityMatcher(it) => (it.operator.with(it.value.clone()))(s),
            SelectorMatchers::SetMatcher(it) => match it.operator {
                Operator::In => it.values.contains(&s),
                Operator::NotIn => !it.values.contains(&s),
                Operator::Exists => !s.is_empty(),
                Operator::NotExists => s.is_empty(),
            },
        }
    }
}

pub mod equality_matcher {
    use super::SelectorMatcher;
    use std::fmt::Display;

    pub struct EqualityMatcher {
        pub operator: Operator,
        pub key: String,
        pub value: String,
    }

    // 实现 Operator 枚举和相关逻辑
    pub enum Operator {
        Equal,
        NotEqual,
    }

    impl Operator {
        // 根据操作符创建匹配函数
        pub fn with(&self, value: String) -> Box<dyn Fn(String) -> bool + Send + Sync> {
            match self {
                Operator::Equal => Box::new(move |arg| arg == value),
                Operator::NotEqual => Box::new(move |arg| arg != value),
            }
        }
    }

    impl EqualityMatcher {
        pub fn to_string(&self) -> String {
            format!("{} {} {}", self.key, self.operator.to_string(), self.value)
        }
        // 创建等值匹配器
        pub fn equal(key: String, value: String) -> Self {
            EqualityMatcher {
                operator: Operator::Equal,
                key,
                value,
            }
        }

        // 创建不等值匹配器
        pub fn not_equal(key: String, value: String) -> Self {
            EqualityMatcher {
                operator: Operator::NotEqual,
                key,
                value,
            }
        }
    }

    // 为 Operator 枚举实现 ToString trait
    impl Display for Operator {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            let str = match self {
                Operator::Equal => "equal".to_string(),
                Operator::NotEqual => "not equal".to_string(),
            };
            write!(f, "{}", str)
        }
    }
}

pub mod set_matcher {
    use ordermap::OrderSet;
    use std::collections::HashSet;

    #[derive(Clone, Debug)]
    pub enum Operator {
        In,
        NotIn,
        Exists,
        NotExists,
    }

    // SetMatcher 结构体
    pub struct SetMatcher {
        pub(crate) key: String,
        pub(crate) operator: Operator,
        pub(crate) values: OrderSet<String>,
    }

    impl SetMatcher {
        // 构造函数
        pub fn new(key: String, operator: Operator) -> Self {
            SetMatcher {
                key,
                operator,
                values: OrderSet::new(),
            }
        }

        fn with(key: String, operator: Operator, values: Vec<String>) -> Self {
            SetMatcher {
                key,
                operator,
                values: values.into_iter().collect::<OrderSet<_>>(),
            }
        }

        // 静态方法创建实例
        pub fn in_values(key: String, values: OrderSet<String>) -> Self {
            SetMatcher {
                key,
                operator: Operator::In,
                values,
            }
        }

        pub fn not_in(key: String, values: Vec<String>) -> Self {
            Self::with(key, Operator::NotIn, values)
        }

        pub fn exists(key: String) -> Self {
            Self::new(key, Operator::Exists)
        }

        pub fn not_exists(key: String) -> Self {
            Self::new(key, Operator::NotExists)
        }
        fn contains(values: &HashSet<String>, value: &str) -> bool {
            values.contains(value)
        }
    }
}

pub struct LabelSelector {
    pub matchers: Vec<SelectorMatchers>,
}

impl LabelSelector {
    pub fn new(matchers: Vec<SelectorMatchers>) -> Self {
        LabelSelector { matchers }
    }

    pub(crate) fn test(&self, labels: HashMap<String, String>) -> bool {
        let matchers = &self.matchers;
        if matchers.is_empty() {
            return true;
        }

        matchers
            .iter()
            .all(|m| m.test(str_util::option_str(labels.get(&m.get_key()))))
    }

    pub(crate) fn and(&mut self, other: LabelSelector) {
        for x in other.matchers {
            self.matchers.push(x);
        }
    }
}

impl Display for LabelSelector {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "LabelSelector")
    }
}

pub struct LabelSelectorBuilder {
    pub matchers: Vec<SelectorMatchers>,
}
impl LabelSelectorBuilder {
    pub fn builder() -> Self {
        LabelSelectorBuilder { matchers: vec![] }
    }
    pub fn eq(mut self, key: &str, value: &str) -> Self {
        self.matchers
            .push(SelectorMatchers::EqualityMatcher(EqualityMatcher::equal(
                key.to_string(),
                value.to_string(),
            )));
        self
    }
    pub fn not_eq(mut self, key: String, value: String) -> Self {
        self.matchers.push(SelectorMatchers::EqualityMatcher(
            EqualityMatcher::not_equal(key, value),
        ));
        self
    }
    pub fn in_(mut self, key: String, values: OrderSet<String>) -> Self {
        self.matchers
            .push(SelectorMatchers::SetMatcher(SetMatcher::in_values(
                key, values,
            )));
        self
    }

    pub fn not_in(mut self, key: String, values: Vec<String>) -> Self {
        self.matchers
            .push(SelectorMatchers::SetMatcher(SetMatcher::not_in(
                key, values,
            )));
        self
    }

    pub fn exists(mut self, key: String) -> Self {
        self.matchers
            .push(SelectorMatchers::SetMatcher(SetMatcher::exists(key)));
        self
    }

    pub fn not_exists(mut self, key: String) -> Self {
        self.matchers
            .push(SelectorMatchers::SetMatcher(SetMatcher::not_exists(key)));
        self
    }

    pub fn build(self) -> LabelSelector {
        LabelSelector {
            matchers: self.matchers,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use equality_matcher::EqualityMatcher;
    #[test]
    fn test1() {
        let matcher = SelectorMatchers::EqualityMatcher(EqualityMatcher::equal(
            "key".to_string(),
            "value".to_string(),
        ));
        assert!(!matcher.test("key=value".to_string()));
    }

    #[test]
    fn test_equal_matcher() {
        let matcher = SelectorMatchers::EqualityMatcher(EqualityMatcher::equal(
            "key".to_string(),
            "value".to_string(),
        ));
        assert_eq!(matcher.get_key(), "key");
        assert!(matcher.test("value".to_string()));
        assert!(!matcher.test("not_value".to_string()));
    }

    #[test]
    fn test_not_equal_matcher() {
        let matcher = SelectorMatchers::EqualityMatcher(EqualityMatcher::not_equal(
            "key".to_string(),
            "value".to_string(),
        ));
        assert_eq!(matcher.get_key(), "key");
        assert!(!matcher.test("value".to_string()));
        assert!(matcher.test("not_value".to_string()));
    }

    #[test]
    fn test_to_string() {
        let matcher = EqualityMatcher::equal("key".to_string(), "value".to_string());
        assert_eq!(matcher.to_string(), "key equal value");
    }
}
